using System;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace FShaderInspector
{
    public partial class FShaderGUI
    {
        void LabelDrawer()
        {
            _basePropertyAttributes.Clear();
            _selectPropertyAttributes.Clear();

            for (var i = 0; i < _properties.Length; i++)
            {
                var prop = _properties[i];

                // 记录当前运行index
                _currentRunIndex = i;

                // 屏蔽属性和隐藏的属性，直接跳过继续
                if (IsFilterProperty(prop) || prop.flags == MaterialProperty.PropFlags.HideInInspector)
                    continue;

                // 是否跳过后续绘制
                var isSkipDraw = false;

                // 是否绘制后面的标签
                var isDrawLaterLabels = true;

                // 获取标签
                var attributes = _material.shader.GetPropertyAttributes(i);
                foreach (var attribute in attributes)
                {
                    // 拆分标签、标签属性
                    var label = attribute.Split('(')[0];
                    var labelProperties = StringUtils.GetLittleBracketsValue(attribute).Split(',');

                    // ------ Base Drawer ------
                    if (label == BaseDrawer)
                    {
                        if (!LogPropTypeError(prop, label))
                        {
                            var data = new PropertyAttributeData
                            {
                                property = prop,
                                keywords = new[] { labelProperties[0] }
                            };
                            _basePropertyAttributes.Add(data);
                        }
                        isSkipDraw = true;
                    }

                    // ------ Foldout Drawer & Enable Drawer & Select Drawer ------
                    // 这些标签为层级标签无法受到别的标签影响，使用 MaterialPropertyDrawer，记录绘制折叠页 index 并且设定后续跳过
                    if (label == FoldoutDrawer || label == EnableDrawer || label == SelectDrawer)
                    {
                        if (label == SelectDrawer)
                        {
                            var data = new PropertyAttributeData
                            {
                                property = prop,
                                keywords = new[] { labelProperties[0] }
                            };
                            _selectPropertyAttributes.Add(data);
                        }

                        _materialEditor.ShaderProperty(prop, prop.displayName);
                        _currentDrawerIndex = i;
                        isSkipDraw = true;
                    }

                    // ------ Break Drawer ------
                    if (label == BreakDrawer)
                    {
                        var newLevel = int.Parse(labelProperties[0]);

                        // 打断 level 低于当前 level 则不执行 1 > 2
                        if (!(newLevel > level))
                        {
                            level = newLevel;
                            isOpen = true;
                        }
                    }

                    // 如果未打开或是子级则跳过继续
                    if (!isOpen && IsChild())
                        continue;

                    // ------ ShowIf Drawer ------
                    if (label == ShowIfDrawer)
                    {
                        var keyword = labelProperties[0];
                        if (!HasMixedKeyword(keyword) && _material.IsKeywordEnabled(keyword))
                        {
                            // 判定是否存在 Space 标签确认最后绘制长度
                            // 默认只有一个 ShowIf 标签时做最后绘制，存在 Space 标签时则判断为2，并且绘制 Space 间隔
                            var lastDrawLength = 1;
                            foreach (var item in attributes)
                            {
                                var itemLabel = item.Split('(')[0];
                                var itemLabelProperties = StringUtils.GetLittleBracketsValue(item).Split(',');
                                if (itemLabel == "Space")
                                {
                                    GUILayout.Space(int.TryParse(itemLabelProperties[0], out var spaceValue) ? spaceValue : 10);
                                    lastDrawLength = 2;
                                    break;
                                }
                            }

                            // 根据抽屉数量做最后的绘制
                            if (attributes.Length == lastDrawLength)
                            {
                                DrawProperty(prop, ContainsLabelDrawer(attributes, ScaleOffsetDrawer));
                                isDrawLaterLabels = false;
                            }
                            else
                            {
                                isDrawLaterLabels = true;
                            }
                        }
                        else
                        {
                            isDrawLaterLabels = false;
                        }

                        isSkipDraw = true;
                    }

                    // ------ HideIf Drawer ------
                    if (label == HideIfDrawer)
                    {
                        var keyword = labelProperties[0];
                        if (!HasMixedKeyword(keyword) && !_material.IsKeywordEnabled(keyword))
                        {
                            // 判定是否存在 Space 标签确认最后绘制长度
                            // 默认只有一个 ShowIf 标签时做最后绘制，存在 Space 标签时则判断为2，并且绘制 Space 间隔
                            var lastDrawLength = 1;
                            foreach (var item in attributes)
                            {
                                var itemLabel = item.Split('(')[0];
                                var itemLabelProperties = StringUtils.GetLittleBracketsValue(item).Split(',');
                                if (itemLabel == "Space")
                                {
                                    GUILayout.Space(int.TryParse(itemLabelProperties[0], out var spaceValue) ? spaceValue : 10);
                                    lastDrawLength = 2;
                                    break;
                                }
                            }

                            // 根据抽屉数量做最后的绘制
                            if (attributes.Length == lastDrawLength)
                            {
                                DrawProperty(prop, ContainsLabelDrawer(attributes, ScaleOffsetDrawer));
                                isDrawLaterLabels = false;
                            }
                            else
                            {
                                isDrawLaterLabels = true;
                            }
                        }
                        else
                        {
                            isDrawLaterLabels = false;
                        }

                        isSkipDraw = true;
                    }

                    // ------ Exist Drawer ------
                    if (label == ExistDrawer)
                    {
                        var keyword = labelProperties[0];

                        if (prop.hasMixedValue)
                            return;

                        if (prop.textureValue)
                        {
                            foreach (var mat in _materials)
                            {
                                if (mat.IsKeywordEnabled(keyword))
                                    continue;

                                TryEnableKeyword(mat, keyword);
                            }
                        }
                        else
                        {
                            foreach (var mat in _materials)
                            {
                                if (!mat.IsKeywordEnabled(keyword))
                                    continue;

                                TryDisableKeyword(mat, keyword);
                            }
                        }
                    }

                    // ------ Nonzero Drawer ------
                    if (label == NonzeroDrawer)
                    {
                        var keyword = labelProperties[0];

                        if (!prop.hasMixedValue)
                        {
                            // float 类型
                            if (prop.type == MaterialProperty.PropType.Float || prop.type == MaterialProperty.PropType.Int || prop.type == MaterialProperty.PropType.Range)
                            {
                                if (prop.floatValue > 0)
                                {
                                    foreach (var mat in _materials)
                                    {
                                        if (mat.IsKeywordEnabled(keyword))
                                            continue;

                                        TryEnableKeyword(mat, keyword);
                                    }
                                }
                                else
                                {
                                    foreach (var mat in _materials)
                                    {
                                        if (!mat.IsKeywordEnabled(keyword))
                                            continue;

                                        TryDisableKeyword(mat, keyword);
                                    }
                                }
                            }
                            else if (prop.type == MaterialProperty.PropType.Vector)
                            {
                                if (prop.vectorValue != Vector4.zero)
                                {
                                    foreach (var mat in _materials)
                                    {
                                        if (mat.IsKeywordEnabled(keyword))
                                            continue;

                                        TryEnableKeyword(mat, keyword);
                                    }
                                }
                                else
                                {
                                    foreach (var mat in _materials)
                                    {
                                        if (!mat.IsKeywordEnabled(keyword))
                                            continue;

                                        TryDisableKeyword(mat, keyword);
                                    }
                                }
                            }
                            else
                            {
                                var message = $"<color=#FFCC66>FShader Inspector：</color>'{prop.name}' 的[{label}]标签支持属性类型必须是 'Float / Int / Range / Vector'类型。当前使用的是 '{prop.type}'类型， GUI 绘制存在问题！！！";
                                Debug.LogWarning(message);
                            }
                        }
                    }

                    // ------ 处理有GUI绘制的标签 ------
                    if (isDrawLaterLabels)
                    {
                        // ------ ScaleOffset Drawer ------
                        if (label == ScaleOffsetDrawer)
                        {
                            if (!LogPropTypeError(prop, label, MaterialProperty.PropType.Texture))
                                DrawProperty(prop, true);

                            isSkipDraw = true;
                        }

                        // ------ IntEnum Drawer ------
                        if (label == IntEnumDrawer)
                        {
                            if (!LogPropTypeError(prop, label))
                            {
                                var keywords = StringUtils.GetLittleBracketsValue(attribute).Split(',');
                                keywords = keywords.Select(keyword => keyword.Trim()).ToArray();

                                _materialEditor.PopupShaderProperty(prop, Localization.FindName(prop.displayName), keywords);
                            }
                            isSkipDraw = true;
                        }

                        // ------ TwoToggle Drawer ------
                        if (label == TwoToggleDrawer)
                        {
                            if (!LogPropTypeError(prop, label, MaterialProperty.PropType.Vector))
                                DrawTwoToggleDrawer(prop, attribute);

                            isSkipDraw = true;
                        }

                        // ------ Vector2 Drawer ------
                        if (label == Vector2Drawer)
                        {
                            if (!LogPropTypeError(prop, label, MaterialProperty.PropType.Vector))
                                _materialEditor.Vector2ShaderProperty(prop, Localization.FindName(prop.displayName));

                            isSkipDraw = true;
                        }

                        // ------ Vector3 Drawer ------
                        if (label == Vector3Drawer)
                        {
                            if (!LogPropTypeError(prop, label, MaterialProperty.PropType.Vector))
                                _materialEditor.Vector3ShaderProperty(prop, Localization.FindName(prop.displayName));

                            isSkipDraw = true;
                        }

                        // ------ Range Drawer ------
                        if (label == RangeDrawer)
                        {
                            if (!LogPropTypeError(prop, label, MaterialProperty.PropType.Vector))
                                DrawRangeDrawer(prop, attribute);
                            isSkipDraw = true;
                        }

                        // ------ 默认 PowerSlider ------
                        if (label == "PowerSlider")
                        {
                            _materialEditor.ShaderProperty(prop, Localization.FindName(prop.displayName));
                            isSkipDraw = true;
                        }
                    }
                }

                // 标签绘制后跳过 避免重复绘制
                if (isSkipDraw)
                    continue;

                // 绘制ShaderGUI
                if (isOpen || !IsChild())
                    DrawProperty(prop);
            }
        }

        /// <summary> 绘制范围 </summary>
        /// <param name="prop">材质属性</param> <param name="attribute">标签属性</param>
        void DrawRangeDrawer(MaterialProperty prop, string attribute)
        {
            MaterialEditor.BeginProperty(prop);

            EditorGUI.showMixedValue = prop.hasMixedValue;

            GUILayout.Label("");
            var rect = GUILayoutUtility.GetLastRect();

            var minmax = StringUtils.GetLittleBracketsValue(attribute);
            var minmaxSp = minmax.Split(',');
            var min = int.Parse(minmaxSp[0]);
            var max = int.Parse(minmaxSp[1]);

            var a = prop.vectorValue.x;
            var b = prop.vectorValue.y;

            EditorGUI.BeginChangeCheck();
            EditorGUI.MinMaxSlider(new Rect(rect.x, rect.y, rect.width * 0.7f, rect.height), Localization.FindName(prop.displayName), ref a, ref b, min, max);
            var sliderVector2 = new Vector2(a, b);
            var fieldVector2 = EditorGUI.Vector2Field(new Rect(rect.width * 0.7f + 50, rect.y, rect.width * 0.3f - 7, rect.height), "", sliderVector2);

            sliderVector2.x = Math.Clamp(fieldVector2.x, min, sliderVector2.y);
            sliderVector2.y = Math.Clamp(fieldVector2.y, sliderVector2.x, max);

            EditorGUI.showMixedValue = false;
            //设置范围属性
            if (EditorGUI.EndChangeCheck())
                prop.vectorValue = new Vector4((float)Math.Round(sliderVector2.x, 3), (float)Math.Round(sliderVector2.y, 3), 0, 0);

            MaterialEditor.EndProperty();
        }

        /// <summary> 绘制双Toggle </summary>
        /// <param name="prop">材质属性</param> <param name="attribute">标签属性</param>
        void DrawTwoToggleDrawer(MaterialProperty prop, string attribute)
        {
            MaterialEditor.BeginProperty(prop);
            EditorGUILayout.BeginHorizontal();

            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = HasMixedValueInVectorComponent(prop, 0);
            var isEnable = EditorGUILayout.Toggle(Localization.FindName(prop.displayName), (int)prop.vectorValue[0] == 1);
            EditorGUI.showMixedValue = false;
            if (EditorGUI.EndChangeCheck())
            {
                var keywords = StringUtils.GetLittleBracketsValue(attribute).Split(',');
                prop.vectorValue = new Vector4(isEnable ? 1 : 0, prop.vectorValue.y, prop.vectorValue.z, prop.vectorValue.w);

                if (keywords.Length != 2)
                    return;

                foreach (var mat in _materials)
                {
                    if (isEnable)
                        TryEnableKeyword(mat, keywords[0]);
                    else
                        TryDisableKeyword(mat, keywords[0]);
                }
            }

            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = HasMixedValueInVectorComponent(prop, 1);
            var isEnable2 = EditorGUILayout.Toggle("", (int)prop.vectorValue[1] == 1);
            EditorGUI.showMixedValue = false;
            if (EditorGUI.EndChangeCheck())
            {
                var keywords = StringUtils.GetLittleBracketsValue(attribute).Split(',');
                prop.vectorValue = new Vector4(prop.vectorValue.x, isEnable2 ? 1 : 0, prop.vectorValue.z, prop.vectorValue.w);

                if (keywords.Length != 2)
                    return;

                foreach (var mat in _materials)
                {
                    if (isEnable2)
                        TryEnableKeyword(mat, keywords[1]);
                    else
                        TryDisableKeyword(mat, keywords[1]);
                }
            }

            EditorGUILayout.EndHorizontal();
            MaterialEditor.EndProperty();
        }

        /// <summary> 检查材质向量属性的指定分量是否具有混合值 </summary>
        /// <param name="prop">属性</param> <param name="index">向量分量索引</param> <returns>混合状态</returns>
        bool HasMixedValueInVectorComponent(MaterialProperty prop, int index)
        {
            // 初始化首个材质的对应分量值
            var initialValue = (int)_materials[0].GetVector(prop.name)[index];

            // 遍历剩余材质，比较向量的指定分量是否一致
            for (var i = 1; i < _materials.Length; i++)
            {
                var currentValue = (int)_materials[i].GetVector(prop.name)[index];
                if (currentValue != initialValue)
                    return true;
            }

            // 全部一致返回false
            return false;
        }

        /// <summary> 检测混合关键字 </summary>
        /// <param name="keyword">关键字</param> <returns>bool</returns>
        bool HasMixedKeyword(string keyword)
        {
            var isMixed = false;

            for (var i = 0; i < _materials.Length; i++)
            {
                var mat = _materials[i];

                if (i == 0) isMixed = mat.IsKeywordEnabled(keyword);
                else
                {
                    if (mat.IsKeywordEnabled(keyword) != isMixed)
                        return true;
                }
            }

            return false;
        }
    }
}